#!/usr/bin/php
<?php
 class InequalitySystem{
  var $variables;    // Переменные
  var $equations;    // Уравнения
  var $warnings_list;// Список warning
  var $changed_variables;// Список изменённых переменных
  
  function __construct($inequalities, $equations){
   $this->warnings_list=array();
   
   // Закидываем переменные
   $this->variables=array();
   foreach ($inequalities as $key => $ineq){
    $tmp =(object)$ineq;
    if (!isset($tmp->min)){  $tmp->min  =null;}
    if (!isset($tmp->value)){$tmp->value=null;}
    if (!isset($tmp->max)){  $tmp->max  =null;}
    $ineq=(object)array(
     'min'  =>$tmp->min,
     'value'=>$tmp->value,
     'max'  =>$tmp->max,
    );
    
    $t=(($ineq->min!==null) ? 1 : 0) + (($ineq->max!==null) ? 2 : 0);
    switch ($t){
     case 0:
      if ($ineq->value===null){
       $this->warnings_list[]='Variable '.$key.' is not defined properly';
       return false;
      }
      break;
     case 1:
      if ($ineq->value===null){
       $ineq->value=$ineq->min;
      }else{
       if ($ineq->value<$ineq->min){
        $this->warnings_list[]='Variable '.$key.'. Current value ('.$ineq->value.') < Minimum value ('.$ineq->min.')';
        $ineq->value=$ineq->min;
       }
      }
      break;
     case 2:
      if ($ineq->value===null){
       $ineq->value=$ineq->max;
      }else{
       if ($ineq->value>$ineq->max){
        $this->warnings_list[]='Variable '.$key.'. Current value ('.$ineq->value.') > Maximum value ('.$ineq->max.')';
        $ineq->value=$ineq->max;
       }
      }
      break;
     case 3:
      if ($ineq->max<$ineq->min){
       $this->warnings_list[]='Variable '.$key.'. Minimum value ('.$ineq->min.') > Maximum value ('.$ineq->max.')';
       return false;
      }elseif($ineq->max==$ineq->min){
       $ineq->value=$ineq->max;
      }elseif($ineq->value===null){
       $ineq->value=(int)round(0.5*$ineq->min+0.5*$ineq->max);
      }elseif($ineq->value<$ineq->min){
       $this->warnings_list[]='Variable '.$key.'. Current value ('.$ineq->value.') < Minimum value ('.$ineq->min.')';
       $ineq->value=$ineq->min;
      }elseif($ineq->value>$ineq->max){
       $this->warnings_list[]='Variable '.$key.'. Current value ('.$ineq->value.') > Maximum value ('.$ineq->max.')';
       $ineq->value=$ineq->max;
      }
      break;
    }
    
    $ineq->min=($ineq->min===null) ? 0 : $ineq->min;
    $this->variables[$key]=$ineq;
   }
   unset($t, $key, $ineq);
   if (count($this->variables)==0){
    $this->warnings_list[]='No variables defined';
    return false;
   }
   
   // Закидываем Уравнения
   $this->equations    =array();
   foreach ($equations as $equation){
    $equation_variables=array();
    foreach (array('key1','key2') as $key){
     $compiled =$equation->{$key};
     $key_variables    =array();
     while (preg_match('_(\\+|\\-|\\/|\\*)?{([a-z0-9-]+)}_i', $compiled, $a)){
      // Ниже проводится анализ переменных
      $key_variables[$a[2]]=(object)array();
      $equation_variables[]=$a[2];
      $compiled =str_replace('{'.$a[2].'}', '$this->variables["'.$a[2].'"]->value', $compiled);
     }
     
     $equation->{$key}=(object)array(
      'compiled' =>$compiled,
      'raw'      =>$equation->{$key},
      'variables'=>$key_variables
     );
     unset($a, $key_variables);
     
     foreach ($equation->{$key}->variables as $key_name => &$key_value){
      // @todo Провести анализ функции. Кроме направления считать ещё и влияние (линейное, геометрическое, сложное)
      $old_value=(int)floor(eval('return '.$compiled.';'));
      $this->variables[$key_name]->value++;
      $new_value=(int)floor(eval('return '.$compiled.';'));
      $key_value->direction=$new_value>$old_value;
      $this->variables[$key_name]->value--;
     }
     //     echo '<pre style="color: orange;">';var_dump($equation->{$key});echo '</pre>';
     unset($compiled, $key_name, $key_value, $new_value, $old_value);
    } // foreach as $key
    $equation->variables=$equation_variables;
    unset($equation_variables, $key);
    
    $this->equations[]=$equation;
   }
   if (count($this->equations)==0){return false;}
   unset($equation);
  }
  
  // Решаем систему
  function solve(){
   $this->changed_variables=array();
   // Первый проход
   for ($eq_num=0;$eq_num<count($this->equations);$eq_num++){
    $equation=&$this->equations[$eq_num];
    if ($this->is_equation_true($equation)){continue;}
    
    //echo '<br>debug: line '.__LINE__.', eq #'.$eq_num;flush();
    if (!$this->try_solve_equation($equation, true)){return false;}
   }
   //echo '<br/><span style="color: red;">line '.__LINE__.'=';var_dump($this->variables);echo '</span>';flush();
   unset($eq_num, $equation);
   
   // Последующие проходы
   for ($iteration_num=0;($this->is_there_unsolved_equation())and($iteration_num<1000);$iteration_num++){
    $a=array();
    foreach ($this->changed_variables as $variable){
     if ($variable!==null){$a[]=$variable;}
    }
    $this->changed_variables=array_unique(array_shuffle($a));
    /* echo '<br>iteration '.$iteration_num.', changed keys: ';flush();$s ='';
    foreach($this->changed_variables as $variable){
     $s.=','.$variable.'='.$this->variables[$variable]->value;
    }
    echo substr($s,1).' | ';$s='';
    foreach($this->equations as $equation){
     $s.=','.($this->is_equation_true($equation) ? 'true' : 'false='.$this->get_offset($equation));
    }
    echo substr($s,1);flush();
    // */
    if (count($this->changed_variables)==0){
     // echo '<br>changed_variables count=0, but there is unsolved equation!';
     for ($eq_num=0;$eq_num<count($this->equations);$eq_num++){
      $equation=&$this->equations[$eq_num];
      if ($this->is_equation_true($equation)){continue;}
      if (!$this->try_solve_equation($equation)){return false;}
      break;
     }
     continue;
    }
    unset($a, $variable, $equation, $s);
    
    // Перебор переменных
    $temp_changed_variables=$this->changed_variables;
    for($i=0;$i<count($temp_changed_variables);$i++){
     $variable =$temp_changed_variables[$i];
     $equation_changed=false;
     // Находим первый eque, в котором упомнена переменная 
     for ($eq_num=0;$eq_num<count($this->equations);$eq_num++){
      $equation=&$this->equations[$eq_num];
      if (!in_array($variable, $equation->variables)){continue;}
      if ($this->is_equation_true($equation)){continue;}
      
      if (!$this->try_solve_equation($equation)){return false;}
      $equation_changed=true;
     } //for $eq_num
     if ($equation_changed){break;}
     
     for ($j=0;$j<count($this->changed_variables);$j++){
      if ($this->changed_variables[$j]==$variable){$this->changed_variables[$j]=null;}
     }
    } // for $i
    unset($variable, $temp_changed_variables, $i, $j);
    
   }  // for $iteration_num
   
   return !($this->is_there_unsolved_equation());
  }
  
  // Смещение между ключами
  protected function get_offset($equation){
   // This is how eval works, bitch!
   $key1=(int)floor(eval('return '.$equation->key1->compiled.';'));
   $key2=(int)floor(eval('return '.$equation->key2->compiled.';'));
   return $key1-$key2;
  }
  
  protected function is_equation_true($equation){
   $offset=$this->get_offset($equation);
   // var_dump($equation, $key1, $key2, $offset);
   // a >= b
   // a < b
   // a = b
   switch ($equation->compare){
    case '==':case '=': return $offset==0; break;
    case '>' :return $offset>0;break;
    case '<' :return $offset<0;break;
    case '>=':case '=>':return $offset>=0; break;
    case '<=':case '=<':return $offset<=0; break;
    default: return null;
   }
  }
  
  protected function is_there_unsolved_equation(){
   for ($eq_num=0;$eq_num<count($this->equations);$eq_num++){
    $equation=$this->equations[$eq_num];
    if (!$this->is_equation_true($equation)){return true;}
   }
   return false;
  }
  
  // Пытаемся привести уравнение в порядок
  protected function try_solve_equation($equation, $no_shuffle=false){
   // Мы считаем, что try_solve_equation вызван не зря, поэтому можно не проверять, что неравенство сходится
   $offset=$this->get_offset($equation);
   
   // Шаг 1: находим направления
   $u =($offset<=0); // Направление движения
   $direction=array(
    -1=>array(),
     1=>array()
   );
   foreach (array('key1','key2') as $key_num){
    foreach ($equation->{$key_num}->variables as $key => $value){
     $num=($u ? 1 : -1)*(($key_num=='key1') ? 1 : -1)*($value->direction ? 1 : -1);
     
     $direction[$num][]=$key;
    }
   }
   
   if (!$no_shuffle){
    $direction[-1]=array_unique(array_shuffle($direction[-1]));
    $direction[1] =array_unique(array_shuffle($direction[1]));
   }else{
    $direction[-1]=array_unique($direction[-1]);
    $direction[1] =array_unique($direction[1]);
   }
   
   unset($key_num, $num, $key, $value, $offset);
   //echo '<br>equation '.$equation->key1->raw.' '.$equation->compare.' '.$equation->key2->raw;
   
   // Шаг 2: Исправляем
   $tmp_array=(!$no_shuffle) ? array_shuffle(array(-1,1)) : array(-1,1);
   foreach($tmp_array as $direction_key){
    switch($direction_key){
     case -1:
      foreach ($direction[-1] as $key){
       $variable =&$this->variables[$key];
       //echo '<br>direction [-1]{'.$key.'}('.$variable->value.'): line '.__LINE__;flush();
       
       $this->changed_variables[]=$key;
       for($variable->value=$variable->value;
           ($variable->min===null) ? true : ($variable->value>$variable->min);){
        if ($this->is_equation_true($equation)){return true;}
        $variable->value--;
        //echo '<br> line '.__LINE__.', `'.$key.'` value='.$variable->value.', min='.$variable->min;
        if ($this->is_equation_true($equation)){return true;}
       }
      }
      break;
     case  1:
      foreach ($direction[1] as $key){
       $variable =&$this->variables[$key];
       //echo '<br>direction [ 1]{'.$key.'}('.$variable->value.'): line '.__LINE__;flush();
       
       $this->changed_variables[]=$key;
       for($variable->value=$variable->value;
           ($variable->max===null) ? true : ($variable->value<$variable->max);){
        if ($this->is_equation_true($equation)){return true;}
        $variable->value++;
        //echo '<br> line '.__LINE__.', `'.$key.'` value='.$variable->value.', max='.$variable->max;
        if ($this->is_equation_true($equation)){return true;}
       }
      }
      break;
    }
   } // foreach(array_shuffle(array(-1,1))
   
   //echo '<br>This equation not solved';
   $this->warnings_list[]='equation ('.$equation->key1->raw.' '.$equation->compare.' '.$equation->key2->raw.') not solved';
   return $this->is_equation_true($equation);
  }
  
  
  
 } // class InequalitySystem 
 
 function array_shuffle($a){
  $b=$a;
  shuffle($b);
  return $b;
 }
 
 function getmicrotime(){
  list($usec, $sec) = explode(" ", microtime()); 
  return ((float)$usec + (float)$sec); 
 }
 
 $profiling_point=array(getmicrotime());
 
// Разбираем параметры
 $options=getopt('i:o:v:', array(
  'no-check',
  'image-width:',
  'min-image-width:',
  'max-image-width:',
  'image-height:',
  'min-image-height:',
  'max-image-height:',
  'screenshot-width:',
  'min-screenshot-width:',
  'max-screenshot-width:',
  'screenshot-height:',
  'min-screenshot-height:',
  'max-screenshot-height:',
  'screenshot-per-line:',
  'screenshots-count:',
  
  'image-paddings:',
  'image-top-padding:',
  'image-right-padding:',
  'image-bottom-padding:',
  'image-left-padding:',
  'screenshot-right-margin:',
  'screenshot-bottom-margin:',
  
  'infoblock-fontsize:',
  
  'no-visible-data',
  'no-video-data',
  'no-audio-data',
  'no-duration',
  'no-filesize',

  'no-screenshot-timestamp',
  
  'image-name-concat', // получать имя конкатинацией с ".jpg"
  
 ));
// @todo Насыщенность скриншотами. Если кол-во скриншотов не задано напрямую
 
 $MIN_EFFECTIVE_WIDTH =200;
 $MIN_EFFECTIVE_HEIGHT=200;
 
 $defaults=array(
  'image-width'             =>1280,
  'min-image-width'         =>0,
  'max-image-width'         =>0,
  'image-height'            =>960,
  'min-image-height'        =>0,
  'max-image-height'        =>0,
  'screenshot-width'        =>0,
  'min-screenshot-width'    =>0,
  'max-screenshot-width'    =>0,
  'screenshot-height'       =>0,
  'min-screenshot-height'   =>0,
  'max-screenshot-height'   =>0,
  'screenshot-per-line'     =>0,
  'screenshots-count'       =>16,
  
  'image-paddings'          =>10,
  'image-top-padding'       =>10,
  'image-right-padding'     =>10,
  'image-bottom-padding'    =>10,
  'image-left-padding'      =>10,
  'screenshot-right-margin' =>10,
  'screenshot-bottom-margin'=>10,
  
  'infoblock-fontsize'      =>14,
 );
 
// V Quite. 0 - quiet, 1 - error, 2 - warning, 3 - info
 if (isset($options['v'])){
  switch($options['v']){
   case 'quiet':$show_warnings_rate=0;break;
   case 'error':$show_warnings_rate=1;break;
   case 'warning':$show_warnings_rate=2;break;
   case 'info' :$show_warnings_rate=3;break;
   default: $show_warnings_rate=1;
  }
 }else{
  $show_warnings_rate=1;
 }
 
 function print_message($text, $rate=1){
  if ($rate<=$GLOBALS['show_warnings_rate']){
   echo $text."\r\n";
  }
 }
 
 
 if (isset($options['image-paddings'])and((int)$options['image-paddings']>0)){
  foreach (array('image-top-padding','image-right-padding','image-bottom-padding','image-left-padding') as $key){
   $options[$key]=isset($options[$key]) ? $options[$key] : (int)$options['image-paddings'];
  }
 }
 
 foreach (array('image-width', 'min-image-width', 'max-image-width',
                'image-height', 'min-image-height', 'max-image-height',
                'screenshot-width', 'min-screenshot-width', 'max-screenshot-width',
                'screenshot-height', 'min-screenshot-height', 'max-screenshot-height', 'screenshot-per-line',
                
                'image-paddings', 'image-top-padding', 'image-right-padding', 'image-bottom-padding', 'image-left-padding',
                'screenshot-right-margin', 'screenshot-bottom-margin',
               ) as $key){
  if (isset($options[$key])){
   $options[$key]=(int)$options[$key];
  }else{
   $options[$key]=0;
  }
 }
 
 foreach (array('image-width', 'image-height', 'screenshot-width', 'screenshot-height') as $key){
  if (($options[$key]>0)and($options['min-'.$key]>0)){
   $options['max-'.$key]=$options[$key];
   $options[$key]=0;
  }
  
  if (($options[$key]>0)and($options['max-'.$key]>0)){
   $options['min-'.$key]=$options[$key];
   $options[$key]=0;
  }
  
  if (($options['min-'.$key]>$options['max-'.$key])and($options['max-'.$key]>0)){
   print_message('min-'.$key.' ('.$options['min-'.$key].') > '.'max-'.$key.' ('.$options['max-'.$key].")");
   return;
  }
 }
 unset($key);
 
// filename, thumbnail_filename
 if ($options['i']==''){
  print_message("filename is empty");
  return;
 }
 $filename=(substr($options['i'],0,1)=='/') ? $options['i'] : getcwd().'/'.$options['i'];
 $filename=preg_replace('|/[^/]*/\\.\\./|', '/', $filename);
 $filename=preg_replace('|/\\./|', '/', $filename);
 //var_dump($filename);
 
 if (is_dir($filename)){
  print_message($filename." is a directory");
  return;
 }
 if (!file_exists($filename)){
  print_message($filename." is not exists");
  return;
 }
 
 $plain_file_name=basename($filename);
 if ($plain_file_name==''){
  print_message($filename." is a directory path");
  return;
 }
 $thumbnail_filename=isset($options['o']) ? $options['o'] : (
  isset($options['image-name-concat']) ? $plain_file_name.'.jpg' : preg_replace('|\\.([^\\.]*)$|','',$plain_file_name).'.jpg'
 );
 print_message("input filename: {$filename}\r\noutput filename: {$thumbnail_filename}", 3);
 
 $profiling_point[]=getmicrotime();
// Получаем данные о файле
 ob_start();
 $tmp_filename='/tmp/'.mt_rand(10000000,99999999).'.tmp';
 exec('ffprobe -show_format -show_streams -print_format json -v quiet "'.$filename.'" > '.$tmp_filename);
 ob_end_clean();
 $filejson=json_decode(file_get_contents($tmp_filename));
 unlink($tmp_filename);
// var_dump($filejson);
 $filedata=(object)array(
  'width' =>null,
  'height'=>null,
  'video' =>null,
  'audio' =>null,
  'duration'=>$filejson->format->duration,
  'effective-duration'=>$filejson->format->duration,// Эффективная. В будущем может быть не равна реальной
  'size'  =>filesize($filename)
 );
 foreach ($filejson->streams as $stream){
  switch ($stream->codec_type){
   case 'audio':$filedata->audio=$stream->codec_long_name;break;
   case 'video':$filedata->video=$stream->codec_long_name;$filedata->width=$stream->width;$filedata->height=$stream->height;break;
  }
 }
 unset($stream);
// var_dump($filedata);
 $profiling_point[]=getmicrotime();
 
// @todo Исходя из продолжительности видео выбирать кол-во скриншотов: screenshot-count
 
 
 
// Правим минимальный и максимальный размер изображения, если заданы опции
 foreach (array('image-width', 'image-height') as $key){
  if (!($options[$key])){
   if (!($options['min-'.$key]) and !($options['max-'.$key])){
    $options[$key]=$defaults[$key];
   }else{
    $options[$key]=(($options['min-'.$key]>0)and($options['max-'.$key]>0))
     ? ceil(0.5*$options['min-'.$key]+0.5*$options['max-'.$key])
     : ( ($options['min-'.$key]>0) ? $options['min-'.$key] : $options['max-'.$key] );
   }
  }else{
   $options['min-'.$key]=($options['min-'.$key]==0) ? $options[$key] : $options['min-'.$key];
   $options['max-'.$key]=($options['max-'.$key]==0) ? $options[$key] : $options['max-'.$key];
  }
 }
 
 $draw_file_data  =!isset($options['no-visible-data']);
 $block_height    =$draw_file_data ? 75 : 0; // @todo переделать
 
// Правим паддинги
 foreach (array('image-top-padding','image-right-padding','image-bottom-padding','image-left-padding') as $key){
  $options[$key]=$options[$key] ? $options[$key] : $defaults[$key];
 }
 
// Считаем эффективные размеры
// @todo Не срезаем сверху и снизу
 foreach (array('width','height') as $key){
  foreach (array('','min-','max-') as $prefix){
   $tmp =$options[$prefix.'image-'.$key];
   if ($tmp==0){
    $options[$prefix.'effective-'.$key]=0;
    continue;
   }
   switch($key){
    case 'width' :$tmp-=$options['image-left-padding']+$options['image-right-padding'];break;
    case 'height':$tmp-=$options['image-top-padding'] +$options['image-bottom-padding']+$block_height;break;
   }
   $options[$prefix.'effective-'.$key]=$tmp;
  }
  
  $current_min=($key=='width') ? $MIN_EFFECTIVE_WIDTH : $MIN_EFFECTIVE_HEIGHT;
  if ($options['effective-'.$key]<$current_min){
   if (($options['max-effective-'.$key]<$current_min)and($options['max-effective-'.$key]>0)){
    // @todo Править паддинги и рейзить warning
    print_message('Error: max-effective-'.$key.' ('.$options['max-effective-'.$key].") < minimal {$key} ({$current_min})");
    return;
   }
   print_message('Warning: effective-'.$key.' ('.$options['effective-'.$key].") < minimal {$key} ({$current_min})", 2);
   
   $offset=$current_min-$options['effective-'.$key];
   foreach (array('image-'.$key, 'effective-'.$key, 'min-image-'.$key, 'min-effective-'.$key) as $a){
    $options[$a]+=$offset;
   }
  }
  
 }
 unset($key, $prefix, $current_min, $offset, $a, $tmp);
 
 print_message("effective size: ".$options['effective-width']."x".$options['effective-height'], 3);
 
/*
 * Заставляем железный мозг сам решать систему неравенств
 */
 function zero_to_null($value, $default_value=null){
  return ($value>0) ? $value : $default_value;
 }
 
// Описываем переменные
 $variables=array(
  'effective-width'  =>(object)array(
   'min'  =>zero_to_null($options['min-effective-width']),
   'value'=>zero_to_null($options['effective-width']),
   'max'  =>zero_to_null($options['max-effective-width']),
  ),
  'effective-height' =>(object)array(
   'min'  =>zero_to_null($options['min-effective-height']),
   'value'=>zero_to_null($options['effective-height']),
   'max'  =>zero_to_null($options['max-effective-height']),
  ),
  
  'screenshot-width' =>(object)array(
   'min'  =>zero_to_null($options['min-screenshot-width'], 10),
   'value'=>zero_to_null($options['screenshot-width'], 250),
   'max'  =>(zero_to_null($options['max-screenshot-width']) !==null) ? zero_to_null($options['max-screenshot-width'])  : $filedata->width
  ),
  'screenshot-height'=>(object)array(
   'min'  =>zero_to_null($options['min-screenshot-height'], 6),
   'value'=>zero_to_null($options['screenshot-height'], 141),
   'max'  =>(zero_to_null($options['max-screenshot-height'])!==null) ? zero_to_null($options['max-screenshot-height']) : $filedata->height
  ),
  
  'margin-bottom'    =>(object)array(
   'min'  =>1,
   'value'=>zero_to_null($options['screenshot-bottom-margin'], 10)
  ),
  'margin-right'     =>(object)array(
   'min'  =>1,
   'value'=>zero_to_null($options['screenshot-right-margin'], 10)
  ),
  
  'screenshot-per-line'=>(object)array(
   'min'  =>max($options['screenshot-per-line'], 1),
   'value'=>max($options['screenshot-per-line'], 10)
  ),
  'screenshot-lines' =>(object)array(
   'min'  =>1,
   'value'=>8,
   'max'  =>100
  ),
  
  'screenshot-count' =>(object)array(
   'min'  =>min($options['screenshots-count'], 16),
   'value'=>$options['screenshots-count'],
   'max'  =>$options['screenshots-count']+4
  ),
  
 );
 
// Описываем систему взаимодействий
 $equations_array=array(
  (object)array(
   'key1'   =>'({effective-width}+{margin-right})-({screenshot-width}+{margin-right})*{screenshot-per-line}',
   'key2'   =>'0',
   'compare'=>'>='
  ),
  (object)array(
   'key1'   =>'({effective-height}+{margin-bottom})-({screenshot-height}+{margin-bottom})*{screenshot-lines}',
   'key2'   =>'0',
   'compare'=>'>='
  ),
  
  (object)array(
   'key1'   =>'{screenshot-count}',
   'key2'   =>'{screenshot-per-line}*{screenshot-lines}',
   'compare'=>'=<'
  ),
  (object)array(
   'key1'   =>'{screenshot-count}',
   'key2'   =>'{screenshot-per-line}*{screenshot-lines}',
   'compare'=>'=>'
  ),
  (object)array(
   'key1'   =>'{screenshot-width}*('.$filedata->height.'/'.$filedata->width.')-{screenshot-height}',
   'key2'   =>'-4',
   'compare'=>'=>'
  ),
  (object)array(
   'key1'   =>'{screenshot-width}*('.$filedata->height.'/'.$filedata->width.')-{screenshot-height}',
   'key2'   =>'4',
   'compare'=>'<='
  ),
  
 );
 
 $profiling_point[]=getmicrotime();
 $system=new InequalitySystem($variables, $equations_array);
// var_dump($variables);
// var_dump($system->variables);
// file_put_contents('/tmp/variables.serialized', serialize($variables));
// file_put_contents('/tmp/filedata.serialized',  serialize($filedata));
 unset($variables, $equations_array);
 
 if (!$system->solve()){
  print_message("Can not find settings for photos", 1);
  foreach ($system->warnings_list as $message){
   print_message($message, 1);
  }
  if ($show_warnings_rate>=3){
   foreach ($system->variables as $key => $value){
    print_message('Variable `'.$key.'` = '.$value->value, 3);
   }
  }
  return;
 }
 foreach ($system->warnings_list as $message){
  print_message('Warning: '.$message, 2);
 }
 $profiling_p1oint[]=getmicrotime();
 
 foreach (array(
   'effective-width'    =>'effective-width',
   'effective-height'   =>'effective-height',
   'screenshot-width'   =>'screenshot-width',
   'screenshot-height'  =>'screenshot-height',
   'margin-bottom'      =>'screenshot-bottom-margin',
   'margin-right'       =>'screenshot-right-margin',
   'screenshot-per-line'=>'screenshot-per-line',
   'screenshot-lines'   =>'screenshot-lines',
   'screenshot-count'   =>'screenshot-count'
  ) as $key => $value){
  $options[$value]=$system->variables[$key]->value;
  print_message('Solved variable `'.$key.'` = '.$system->variables[$key]->value, 3);
 }
 unset($key, $value, $system);
 
// Удаляем лишние размеры на картинке
// Уменьшаем resolution картинки
 while (
  ($options['effective-width']+$options['screenshot-right-margin']>
    $options['screenshot-per-line']*($options['screenshot-width']+$options['screenshot-right-margin']))
  and
  (($options['effective-width']>$options['min-effective-width'])or($options['min-effective-width']==0))
 ){
  $options['effective-width']--;
 }
 while (
  ($options['effective-height']+$options['screenshot-bottom-margin']>
    $options['screenshot-lines']*($options['screenshot-height']+$options['screenshot-bottom-margin']))
  and
  (($options['effective-height']>$options['min-effective-height'])or($options['min-effective-height']==0))
 ){
  $options['effective-height']--;
 }
 
// Увеличиваем margin'ы скриншотов
// @todo проверить "последний margin"
 while ($options['screenshot-per-line']*($options['screenshot-width']+$options['screenshot-right-margin']+1) <= $options['effective-width']){
  $options['screenshot-right-margin']++;
 }
 while ($options['screenshot-lines']*($options['screenshot-height']+$options['screenshot-bottom-margin']+1)  <= $options['effective-height']){
  $options['screenshot-bottom-margin']++;
 }
// Считаем реальные размеры скринлиста, танцуя от эффективных размеров
 $options['image-height']=$options['effective-height']+$options['image-top-padding'] +$options['image-bottom-padding']+$block_height;
 $options['image-width'] =$options['effective-width'] +$options['image-left-padding']+$options['image-right-padding'];
 
// Шаг #2: режем видео на скриншоты
 $options['screenshot-fps']=$options['screenshot-count']/floor($filedata->{'effective-duration'});
 ob_start();
 $random_prefix=mt_rand(1000000,9999999);
 exec('ffmpeg -i '.$filename.' -vf fps='.$options['screenshot-count'].'/'.floor($filedata->{'effective-duration'}).
      ' -qscale:v 2 -format jpg -quality 100 -f image2 /tmp/thumb'.$random_prefix.'-%0d.jpg > /dev/null');
 ob_end_clean();
 $profiling_point[]=getmicrotime();
 
// Теперь у нас есть картинки типа /tmp/thumb10-1.jpg.tmp
// Шаг #3: создаём белый лист
 exec('convert -size '.$options['image-width'].'x'.$options['image-height'].
      ' xc:wheat -format jpg -quality 100 /tmp/screen'.$random_prefix.'.jpg');
 $profiling_point[]=getmicrotime();
 
// Рисуем на него данные
 if ($draw_file_data){
  $options['infoblock-fontsize']=isset($options['infoblock-fontsize']) ? (int)$options['infoblock-fontsize'] : $defaults['infoblock-fontsize'];
  if ($filedata->size>1024*1024){
   $filesize=(floor(100*$filedata->size/1024/1024)/100).'MB';
  }elseif ($filedata->size>1024*1024*1024){
   $filesize=(floor(100*$filedata->size/1024/1024/1024)/100).'GB';
  }else{
   $filesize='';
  }
  
  $a=$filedata->width;
  $b=$filedata->height;
  while ($a!=$b){
   if ($a>$b){
    $a-=$b;
   }else{
    $b-=$a;
   }
  }
  $gcd=$a;
  
  $array=array(
   (object)array(
    'x'=>0,
    'y'=>0,
    'title'=>'Filename: '.$plain_file_name
   )
  );
  
  // @todo переделать это, координаты неправильны, если один или более элементов невидимы
  if (!isset($options['no-duration'])){
   $array[]=(object)array(
    'x'=>0,
    'y'=>3,
    'title'=>'Duration: '.gmdate('H:i:s', floor($filedata->duration)).substr($filedata->duration-floor($filedata->duration), 1, 4)
   );
  }
  if (!isset($options['no-filesize'])){
   $array[]=(object)array(
    'x'=>0,
    'y'=>1,
    'title'=>'File size: '.$filesize.' ('.$filedata->size.')'
   );
  }
  if (!isset($options['no-video-data'])){
   $array[]=(object)array(
    'x'=>0,
    'y'=>2,
    'title'=>'Resolution: '.$filedata->width.'x'.$filedata->height.' ('.($filedata->width/$gcd).':'.($filedata->height/$gcd).')'
   );
   $array[]=(object)array(
    'x'=>1,
    'y'=>1,
    'title'=>'Video: '.$filedata->video
   );
  }
  if (!isset($options['no-audio-data'])){
   $array[]=(object)array(
    'x'=>1,
    'y'=>2,
    'title'=>'Audio: '.$filedata->audio
   );
  }
  $array[]=(object)array(
   'x'=>1,
   'y'=>3,
   'title'=>'Created by MkThumbList (https://code.google.com/p/mkthumblist/)'
  );
  
  foreach ($array as $obj){
   // @todo const font-size
   exec("convert /tmp/screen{$random_prefix}.jpg  -fill black -pointsize ".$options['infoblock-fontsize']." -annotate +".
        ($options['image-left-padding']+$obj->x*300).'+'.
        ($options['image-top-padding']+($obj->y)*($options['infoblock-fontsize']+2)+$options['infoblock-fontsize']).
        " '".$obj->title."' /tmp/screen{$random_prefix}.jpg");
  }
  unset($a, $b, $array, $obj, $filesize, $gcd);
 }
 $profiling_point[]=getmicrotime();
 
// Рисуем туда скриншоты
 $image_x=0;
 $image_y=0;
 @unlink('/tmp/thumb'.$random_prefix.'-1.jpg');
 for ($screen_num=2;$screen_num<=$options['screenshot-count']+1;$screen_num++){
  $x=$image_x*($options['screenshot-width'] +$options['screenshot-right-margin']) +$options['image-left-padding'];
  $y=$image_y*($options['screenshot-height']+$options['screenshot-bottom-margin'])+$options['image-top-padding']+$block_height;
  
  exec('composite -geometry '.
       $options['screenshot-width'].'x'.$options['screenshot-height'].'+'.$x.'+'.$y.
       ' /tmp/thumb'.$random_prefix.'-'.$screen_num.'.jpg'.
       ' /tmp/screen'.$random_prefix.'.jpg /tmp/screen'.$random_prefix.'.jpg');
  if (!isset($options['no-screenshot-timestamp'])){
   // @todo поправить бордюр надписи, не читается белым по белому
   $current_duration=max(($screen_num-1.5)/$options['screenshot-fps'],0);
   exec("convert /tmp/screen{$random_prefix}.jpg -fill white -pointsize 10 -annotate +".
        ($x+3).'+'.($y+12)." '".gmdate('H:i:s', $current_duration).
        substr($current_duration-floor($current_duration), 1, 3)."' /tmp/screen{$random_prefix}.jpg");
  }
  
  $image_x++;
  if ($image_x==$options['screenshot-per-line']){
   $image_x=0;
   $image_y++;
  }
  
  @unlink('/tmp/thumb'.$random_prefix.'-'.$screen_num.'.jpg');
 }
 $profiling_point[]=getmicrotime();
 
 @rename("/tmp/screen{$random_prefix}.jpg", $thumbnail_filename);
 if ($show_warnings_rate>=3){var_dump($options);}
 
?>